iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0

昨天我們討論 MVVM 架構,並介紹如何使用 @Published@StateObject 在 SwiftUI 中實現資料與 View 的同步。在練習過程中,我們使用到一個叫做 List 的元件來顯示清單,但還沒有詳細介紹 List 的用途和特性。今天,我們將進一步實作 List,將它整合到主畫面中,用來顯示我們的家用品清單。

List 是什麼?

List 是 SwiftUI 中一個非常常用的元件,有點像 UIKit 中的 UITableView,它被用來顯示一組資料的垂直列表。無論是顯示簡單的文字清單,還是建立複雜的自定義佈局,List 都能輕鬆應對。它內建了滾動和資料更新等功能,非常適合用來展示需要動態更新的資料清單。

List 也支援刪除、複選、多維資料顯示等功能,但由於我們尚未實作資料的異動,這部分會等待至之後再介紹。如果對這些進階功能有興趣,可以參考下方的資料來進一步了解!

參考資料:List | Apple Developer Documentation

使用 List 顯示家用品清單

我們將繼續使用昨天定義的 ItemViewModel,並在主畫面中使用 List 來顯示家用品的名稱和數量。我們回顧一下 ItemViewModel 的結構:

class ItemViewModel: ObservableObject {
    @Published var items: [Item] = [
        Item(name: "牛奶", quantity: 2),
        Item(name: "麵包", quantity: 1)
    ]
    
    func addItem(name: String, quantity: Int) {
        let newItem = Item(name: name, quantity: quantity)
        items.append(newItem)
    }
}

接下來,我們在主畫面中使用 List 來顯示這些資料:

struct ContentView: View {
    @StateObject var viewModel = ItemViewModel()

    var body: some View {
        List(viewModel.items) { item in
            HStack {
                Text(item.name)
                    .font(.headline)
                Spacer()
                Text("數量: \(item.quantity)")
                    .font(.subheadline)
                    .foregroundColor(.gray)
            }
            .padding(.vertical, 8)
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/List-530x1024.webp

分析這段程式碼

  • List(viewModel.items):我們使用 List 來遍歷 viewModel.items,並將每個 Item 顯示為列表中的一行。List 會自動處理資料的佈局,並且當 items 發生變化時,自動更新列表顯示。
  • HStack:每個列表項目使用 HStack 來橫向排列物品的名稱和數量。這樣可以讓列表項目更加整齊有序。
  • Spacer()Spacer 用來在名稱和數量之間增加空間,讓它們對齊兩側。
  • Text:我們使用 Text 來顯示物品名稱和數量,並使用不同的字型和顏色來區分它們。
  • padding(.vertical, 8):為每個列表項目添加垂直間距,使項目之間的間距更加合理。

為什麼使用 List?

List 不僅能夠自動處理資料的顯示與佈局,還能夠在資料變動時自動更新,我們在 ItemViewModel 中使用了 @Published 屬性,這樣一來,當資料發生變化時,List 會立即顯示最新的內容,而不需要我們手動更新 UI。

其他常見的 SwiftUI 列表元件

除了 List,SwiftUI 還提供了其他元件來顯示列表或集合資料。這些元件各有不同的用途和優勢,可以根據不同的需求靈活選擇。

1. ForEach

  • 用途: 用來遍歷集合中的每一個項目,並生成對應的 View。
  • 適用場景: ForEach 通常與 VStackHStackZStack 等元件結合使用,適合用來顯示靜態的佈局或不需要滾動的簡單列表。這種元件適合用在顯示少量固定的項目,或者在自訂 UI 佈局中嵌入多個子元件時使用。
VStack {
    ForEach(0..<5) { index in
        Text("項目 \(index)")
    }
}

https://ooorito.com/wp-content/uploads/2024/08/ForEach-512x1024.webp

參考資料:

2. ScrollView

  • 用途: 容器元件,允許內容在垂直或水平方向上滾動顯示(使用 .horizontal.vertical 控制捲動的方向),常與 ForEach 結合使用。
  • 適用場景: 當內容超出螢幕顯示範圍時,使用 ScrollView 可以讓使用者滾動瀏覽內容。這個元件非常適合用來顯示長列表、圖片庫或其他需要滾動的資料。通常與 ForEachLazyVStack 等元件結合使用。
ScrollView {
    VStack {
        ForEach(0..<50) { index in
            Text("項目 \(index)")
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/ScrollView.gif

參考資料:

3. LazyVStack 和 LazyHStack

  • 用途: LazyVStackLazyHStackVStackHStack 類似,但卻不同。不同於它們僅在需要時才載入內容,這對於顯示大量資料時能夠顯著提高效能。
  • 適用場景: 適合用在需要顯示大量資料列表時,特別是需要滾動查看的長列表,這些元件可以避免一次性載入過多資料,提升效能。
ScrollView {
    LazyVStack {
        ForEach(0..<100) { index in
            Text("項目 \(index)")
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/ScrollView.gif

ScrollView(.horizontal) {
    LazyHStack(spacing: 16) {
        ForEach(0..<100) { index in
            Text("項目 \(index)")
                .padding(.horizontal, 16)
                .padding(.vertical, 8)
                .background(Color.blue.opacity(0.7))
                .foregroundColor(.white)
                .cornerRadius(8)
        }
    }
    .padding()
}

https://ooorito.com/wp-content/uploads/2024/08/LazyHStack.gif

參考資料:

4. LazyVGrid 和 LazyHGrid

  • 用途: LazyVGridLazyHGrid 是用來顯示格狀佈局資料的元件,與 LazyVStackLazyHStack 類似,會在使用時才載入內容。這些元件在大量資料顯示時具有更好的效能表現。
  • 適用場景: 當我們需要以格狀佈局來顯示資料時,例如圖片庫或商品列表,就可以選擇 LazyVGridLazyHGrid。它們能夠靈活處理格子的大小和佈局,適合展示需要多列或多行顯示的內容。
let columns = [
    GridItem(.flexible()),
    GridItem(.flexible())
]

ScrollView {
    LazyVGrid(columns: columns) {
        ForEach(0..<50) { index in
            Text("項目 \(index)")
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/LazyVGrid.gif

let columns = [
    GridItem(.fixed(50)),
    GridItem(.fixed(50))
]

ScrollView(.horizontal) {
    LazyHGrid(rows: columns, spacing: 16) {
        ForEach(0..<50) { index in
            Text("項目 \(index)")
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/LazyHStack.gif

參考資料:

5. Table (僅 macOS)

  • 用途: Table 是專門用於 macOS 的元件,用來顯示表格式資料。
  • 適用場景: 用於在 macOS 應用程式中顯示複雜的表格或資料集,當需要呈現結構化、表格型資料時非常有用。
struct Person: Identifiable {
    let givenName: String
    let familyName: String
    let emailAddress: String
    let id = UUID()


    var fullName: String { givenName + " " + familyName }
}


@State private var people = [
    Person(givenName: "Juan", familyName: "Chavez", emailAddress: 
"juanchavez@icloud.com"),
    Person(givenName: "Mei", familyName: "Chen", emailAddress: "meichen@icloud.com"),
    Person(givenName: "Tom", familyName: "Clark", emailAddress: "tomclark@icloud.com"),
    Person(givenName: "Gita", familyName: "Kumar", emailAddress: "gitakumar@icloud.com")
]


struct PeopleTable: View {
    var body: some View {
        Table(people) {
            TableColumn("Given Name", value: \.givenName)
            TableColumn("Family Name", value: \.familyName)
            TableColumn("E-Mail Address", value: \.emailAddress)
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/image-2-1024x292.png

參考資料:Table | Apple Developer Documentation

總結

今天我們認識 SwiftUI 中顯示列表的各種元件,尤其是 List 元件,並學習了如何使用它來顯示家用品清單。我們還簡單介紹其他幾個常用的列表元件,如 ForEachScrollViewLazyVStackLazyVGrid,這些元件能夠幫助我們更靈活地處理不同類型的資料顯示需求。透過這些元件,我們能夠輕鬆創造出高效、美觀的 UI。

明天,我們將進一步學習如何在列表中新增與刪除項目,敬請期待!


上一篇
Day 8: SwiftUI 中的 MVVM 架構初次使用
下一篇
Day 10: 在 SwiftUI 中實現新增與刪除家用品項目
系列文
用 SwiftUI 掌控家庭日用品庫存30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言